package com.daocheng.dc.book.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.daocheng.dc.book.auth.config.PasswordEncoderConfig;
import com.daocheng.dc.book.auth.constant.RedisKeyConstant;
import com.daocheng.dc.book.auth.enums.LoginTypeEnum;
import com.daocheng.dc.book.auth.enums.ResponseCodeEnum;
import com.daocheng.dc.book.auth.filter.LoginUserContextHolder;
import com.daocheng.dc.book.auth.model.vo.user.UpdatePasswordReqVO;
import com.daocheng.dc.book.auth.model.vo.user.UserLoginReqVO;
import com.daocheng.dc.book.auth.rpc.UserRpcService;
import com.daocheng.dc.book.auth.service.AuthService;
import com.daocheng.dc.book.user.dto.rsp.FindByPhoneRspDTO;
import com.daocheng.framework.common.exception.BizException;
import com.daocheng.framework.common.response.Response;
import com.daocheng.framework.common.utils.JsonUtils;
import com.google.common.base.Preconditions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * @ClassName UserServiceImpl
 * @author: 稻城
 * @date: 2025/3/18
 * @Version 1.0
 * @description: TODO
 */
@Service
@Slf4j
public class AuthServiceImpl implements AuthService {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private PasswordEncoderConfig passwordEncoderConfig;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserRpcService userRpcService;
    /**
     * 声明编程式事务
     */

    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer type = userLoginReqVO.getType();
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);
        Long userId = null;
        switch (loginTypeEnum) {
            case VERIFICATION_CODE://验证码登录
                String verificationCode = userLoginReqVO.getCode();
                Preconditions.checkArgument(StringUtils.isNotBlank(verificationCode), "验证码不能为空");
                //构建验证码redis key
                String key = RedisKeyConstant.buildVerificationCodeKey(phone);
                //获取在Redis的验证码
                String sentCode = (String) redisTemplate.opsForValue().get(key);
                //校验用户提交的验证码和redis存入的是否一致
                if (!StringUtils.equals(verificationCode, sentCode)) {
                    throw new BizException(ResponseCodeEnum.VERIFICATION_CODE_ERROR);
                }
                //自动注册功能
                //注册id
                //todo
                Long userIdTmp = userRpcService.registerUser(phone);
                if (Objects.isNull(userIdTmp)) {
                    throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                }
                userId = userIdTmp;
                break;
            case PASSWORD://密码登录
                String password = userLoginReqVO.getPassword();
                //根据手机号查询用户
                // RPC 调用用户服务 校验手机号和密码
                FindByPhoneRspDTO findByPhoneRspDTO = userRpcService.findByPhone(phone);
                if (Objects.isNull(findByPhoneRspDTO)) {
                    //用户不存在
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }
                String encodePassword = findByPhoneRspDTO.getPassword();
                boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);
                if (!isPasswordCorrect) {
                    //密码错误
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }
                userId = findByPhoneRspDTO.getId();
                break;
            default:
                throw new BizException(ResponseCodeEnum.LOGIN_TYPE_ERROR);
        }
        // SaToken 登录用户，并返回 token 令牌
        StpUtil.login(userId);
        //获取token令牌
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        log.info("==> SaTokenInfo: {}", JsonUtils.toJsonString(tokenInfo));
        return Response.success(tokenInfo.tokenValue);
    }

    @Override
    public Response<?> logout() {
        Long userId = LoginUserContextHolder.getUserId();
        log.info("==> 用户退出登录, userId: {}", userId);
        StpUtil.logout(userId);
        return Response.success();
    }

    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        //新密码
        String newPassword = updatePasswordReqVO.getNewPassword();
        //加密
        String newPasswordEncrypt = passwordEncoderConfig.passwordEncoder().encode(newPassword);
        //调用RPC
        userRpcService.updatePassword(newPasswordEncrypt);
        return Response.success();
    }

}
